package Cantella::DJabberd::Plugin::Authentication;

use strict;
use warnings;

use base 'DJabberd::Authen';

use DJabberd::Log;

our $logger = DJabberd::Log->get_logger;
sub log { $logger }

#config variables
sub set_config_schema {
  my ($self, $schema) = @_;
  #type check here?
  $self->{dbic_schema} = $schema;
}

sub set_config_dsn {
  my ($self, $dbdsn) = @_;
  $self->{dbic_dbdsn} = $dbdsn;
}

sub set_config_dbusername {
  my ($self, $dbusername) = @_;
  $self->{dbic_dbusername} = $dbusername;
}

sub set_config_dbpassword {
  my ($self, $dbpassword) = @_;
  $self->{dbic_dbpassword} = $dbpassword;
}

sub set_config_schemaclass {
  my ($self, $schema_class) = @_;
  $self->{dbic_schema_class} = $schema_class;
}

#Throw exceptions if all our data is not provided.
sub finalize {
  my $self = shift;

  return if eval { $self->{dbic_schema}->isa('DBIx::Class::Schema') };

  $logger->fatal("dsn not provided")      unless $self->{dbic_dbdsn};
  $logger->fatal("username not provided") unless $self->{dbic_dbusername};
  $logger->fatal("password not provided") unless $self->{dbic_dbpassword};

  my $schema = $self->{dbic_schema_class}->connect(
                                                 $self->{dbic_dbdsn},
                                                 $self->{dbic_dbusername},
                                                 $self->{dbic_dbpassword}
                                                );
  #warn("Successfully logged in to the database") if $schema;
  $logger->fatal("Could not connect to the database") unless $schema;
  $self->{dbic_schema} = $schema;
}


#to do: Check digest
#       Plaintext storage support (maybe 2-way encoding?)
#       Inline registration ?

#informational predicates
#We don't do these because, well, they suck.
sub can_register_jids      { 0 } #not strictly necessary, but verbosity never hurts
sub can_unregister_jids    { 0 } #not strictly necessary, but verbosity never hurts

#We can't do these because we don't store plaintext passwords.
sub can_retrieve_cleartext { 0 } #not strictly necessary, but verbosity never hurts
sub can_check_digest       { 0 } #not strictly necessary, but verbosity never hurts

sub get_user_from_jid {
  my ($self,$node,$domain) = @_;
  my $rs = $self->{dbic_schema}->resultset('UserJid')->search
    ( 
     { node => $node, 'domain.hostname' => $domain },
     { join => ['domain'], prefetch => ['user'] }
    );
  if(my $jid = $rs->first){
    return $jid->user;
  }
  return;
}

sub check_cleartext {
  my ($self, $cb, %args) = @_;
  my $node = $args{username};
  my $domain =  $args{conn}->vhost->server_name;
  my $user = $self->get_user_from_jid($node, $domain);
  unless( $user ){
    $logger->info("Failed to find '${node}' in domain '${domain}'");
    return $cb->reject;
  }
  $logger->debug("Checking cleartext password for ".$user->username);
  if( $user->check_password( $args{password} ) ){
    $logger->debug("${node}\@${domain} authenticated sucessfully");
    return $cb->accept;
  }
  $logger->info("Auth failed for user '$username' as '$jid': password error");
  return $cb->reject;
}

sub check_jid {
  my ($self, $cb, %args) = @_;
  my $node = $args{username};
  my $domain =  $args{conn}->vhost->server_name;
  my $jid = $node . '@' . $domain;

  if( defined($self->get_user_from_jid($node, $domain)) ){
    $logger->debug("checked JID '${jid}'");
    return $cb->accept;
  }
  $logger->debug("Can't check JID, failed to find JID '${jid}'");
  return $cb->reject;
}

#We are not supporting plaintext passwords, so fuck it
# sub get_password {
#   my ($self, $cb, %args) = @_;
#   my $node = $args{username};
#   my $domain =  $args{conn}->vhost->server_name;
#   my $jid = $node . '@' . $domain;

#   if( defined(my $user = $self->get_user_from_jid($node, $domain)) ){
#     $cb->set($user->password);
#     return $cb->accept;
#   }

#   $logger->info("Can't get password for '$jid': user not found.");
#   return $cb->reject;
# }

1;
